﻿// ============================================================================
// FileName: SIPAccount.cs
//
// Description:
// Represents a SIP account that holds authentication information and additional settings
// for SIP accounts.
//
// Author(s):
// Aaron Clauson
//
// History:
// 10 May 2008  Aaron Clauson   Created.
//
// License: 
// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2008 Aaron Clauson (aaronc@blueface.ie), Blue Face Ltd, Dublin, Ireland (www.blueface.ie)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd. 
// nor the names of its contributors may be used to endorse or promote products derived from this software without specific 
// prior written permission. 
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
// ============================================================================

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Xml;
using BlueFace.Sys;
using log4net;

#if UNITTEST
using NUnit.Framework;
#endif

namespace BlueFace.VoIP.SIPServerCores.StatefulProxy
{
    public class SIPAccount
    {
        private static ILog logger = AppState.logger;
        
        public Guid SIPAccountId;
        public string Owner;                    // The username of the account that owns this SIP provider configuration.
        public string SIPUsername;
        public string SIPPassword;
        public string SIPDomain;
        public DateTime Inserted;

       // public static Int64 Created;
       // public static Int64 Destroyed;

        /// <summary>
        /// Don't use. For serialisation use only.
        /// </summary>
        public SIPAccount()
        {
            //Created++;
        }

        public SIPAccount(
            string owner, 
            string username, 
            string password, 
            string domain)
        {
            //Created++;

            SIPAccountId = Guid.NewGuid();
            Owner = owner;
            SIPUsername = username; 
            SIPPassword = password;
            SIPDomain = domain;
            Inserted = DateTime.Now;
        }
        
        public SIPAccount(DataRow sipAccountRow)
        {
            //Created++;

            try
            {
                SIPAccountId = (sipAccountRow.Table.Columns.Contains("sipaccountid") && sipAccountRow["sipaccountid"] != null) ? new Guid(sipAccountRow["sipaccountid"] as string) : Guid.NewGuid();
                SIPUsername = sipAccountRow["sipusername"] as string;
                SIPPassword = sipAccountRow["sippassword"] as string;
                SIPDomain = sipAccountRow["domain"] as string;
                Owner = (sipAccountRow.Table.Columns.Contains("owner") && sipAccountRow["owner"] != null) ? sipAccountRow["owner"] as string : SIPUsername;
                Inserted = (sipAccountRow.Table.Columns.Contains("inserted") && sipAccountRow["inserted"] != null) ? Convert.ToDateTime(sipAccountRow["inserted"]) : DateTime.Now;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPAccount. " + excp);
                throw excp;
            }
        }

        public string ToXML()
        {
            string sipAccountXML =
                "<sipaccount>" +
                " <id>" +SIPAccountId + "</id>" +
                " <owner>" + Owner + "</owner>" +
                " <sipusername>" + SIPUsername + "</sipusername>" +
                " <sippassword>" + SIPPassword + "</sippassword>" +
                " <sipdomain>" + SIPDomain + "</sipdomain>" +
                "</sipaccount>";

            return sipAccountXML;
        }

        /*~SIPAccount()
        {
            Destroyed++;
        }*/
    }

    public class SIPAccountPersistor
    {
        private static ILog logger = AppState.logger;

        private StorageLayer m_storageLayer;

        public SIPAccountPersistor(StorageTypes storageType, string dbConnStr)
        {
            m_storageLayer = new StorageLayer(storageType, dbConnStr);
        }

        public SIPAccountPersistor(StorageLayer storageLayer)
        {
            m_storageLayer = storageLayer;
        }

        public void AddOrUpdateSIPAccount(SIPAccount sipAccount)
        {
            try
            {
                string sipAccountOwner = "'" + sipAccount.Owner.Replace("'", "''") + "'";
                string sipAccountUsername = "'" + sipAccount.SIPUsername.Replace("'", "''") + "'";
                string sipAccountPassword = "'" + sipAccount.SIPPassword.Replace("'", "''") + "'";
                string sipDomain = "'" + sipAccount.SIPDomain.Replace("'", "''") + "'";

                string domainId = m_storageLayer.ExecuteScalar("select domainid from domains where domain = " + sipDomain) as string;
                if (domainId == null)
                {
                    domainId = m_storageLayer.ExecuteScalar("select domainid from domainaliases where domainalias = " + sipDomain) as string;
                }

                if (domainId == null)
                {
                    throw new ApplicationException("Cannot persist a SIP account for an unserviced domain " + sipDomain + ".");
                }
                else
                {
                    int count = Convert.ToInt32(m_storageLayer.ExecuteScalar("select count(*) from sipaccounts where sipaccountid = '" + sipAccount.SIPAccountId + "'"));

                    if (count == 1)
                    {
                        string updateSql =
                            "update sipaccounts set " +
                            "sipusername = " + sipAccountUsername + ", " +
                            "sippassword = " + sipAccountPassword + "," +
                            "owner = " + sipAccountOwner + "," +
                            "domainid = '" + domainId + "' " +
                            "where sipaccouuntid = '" + sipAccount.SIPAccountId + "'";

                        logger.Debug(updateSql);

                        m_storageLayer.ExecuteNonQuery(updateSql);
                    }
                    else
                    {
                        string insertSql = "insert into sipaccounts " +
                            "(sipaccountid, " +
                            "owner, " +
                            "sipusername," +
                            "sippassword," +
                            "domainid," +
                            "inserted) " +
                            "values (" +
                            "'" + sipAccount.SIPAccountId + "'," +
                            sipAccountOwner + "," +
                            sipAccountUsername + "," +
                            sipAccountPassword + "," +
                            "'" + domainId + "'," +
                            "default)";

                        logger.Debug(insertSql);

                        m_storageLayer.ExecuteNonQuery(insertSql);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AddOrUpdateSIPAccount. " + excp);
                throw excp;
            }
        }

        public SIPAccount GetSIPAccount(Guid sipAccountId)
        {
            try
            {
                SIPAccount sipAccount = null;

                DataSet sipAccountSet = m_storageLayer.GetDataSet("select * from sipaccounts where sipaccountid = '" + sipAccountId + "'");

                if (sipAccountSet.Tables[0].Rows.Count > 0)
                {
                    sipAccount = new SIPAccount(sipAccountSet.Tables[0].Rows[0]);
                }

                return sipAccount;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetSIPAccount. " + excp);
                throw excp;
            }
        }

        public SIPAccount GetSIPAccount(string sipUsername, string sipDomain)
        {
            try
            {
                SIPAccount sipAccount = null;

                string sipUsernameStr = sipUsername.Replace("'", "''");
                string domainStr = sipDomain.Replace("'", "''");

                DataSet sipAccountSet = m_storageLayer.GetDataSet("select * from sipaccounts sipacc join domains da on sipacc.domainid = da.domainid where sipusername = '" + sipUsernameStr + "' and da.domainid = (select domainid from domains where domain = '" + domainStr + "')");

                if (sipAccountSet.Tables[0].Rows.Count > 0)
                {
                    sipAccount = new SIPAccount(sipAccountSet.Tables[0].Rows[0]);
                }

                return sipAccount;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetSIPAccount. " + excp);
                throw excp;
            }
        }

        public List<SIPAccount> GetSIPAccountsForUser(string username)
        {
            try
            {
                List<SIPAccount> sipAccountsList = new List<SIPAccount>();

                DataSet sipAccountsSet = m_storageLayer.GetDataSet("select * from sipaccounts sipacc join domains da on sipacc.domainid = da.domainid where UPPER(owner) = '" + username.ToUpper() + "' order by sipusername asc");

                if (sipAccountsSet.Tables[0].Rows.Count > 0)
                {
                    foreach (DataRow sipAccountRow in sipAccountsSet.Tables[0].Rows)
                    {
                        sipAccountsList.Add(new SIPAccount(sipAccountRow));
                    }
                }

                return sipAccountsList;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetSIPAccountsForUser. " + excp);
                throw excp;
            }
        }

        public void DeleteSIPAccount(Guid sipAccountId)
        {
            try
            {
                m_storageLayer.ExecuteNonQuery("delete from sipaccounts where sipaccountid = '" + sipAccountId + "'");
            }
            catch (Exception excp)
            {
                logger.Error("Exception DeleteSIPAccount. " + excp);
                throw excp;
            }
        }

        #region Unit testing.

		#if UNITTEST

		[TestFixture]
		public class SIPAccountUnitTest
		{			
			[TestFixtureSetUp]
			public void Init()
			{ }

            [TestFixtureTearDown]
            public void Dispose()
            { }

			[Test]
			public void SampleTest()
			{
				Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
				
				Assert.IsTrue(true, "True was false.");

				Console.WriteLine("---------------------------------"); 
			}
        }

        #endif

        #endregion
    }
}
